#!/usr/bin/python
# Copyright 2011 Alex K (wtwf.com) All rights reserved.

"""
Controls an iTunes instance on the local machine via appescript and http.

Usage: %(PROGRAM)s [options]

Options:
  -p
    listen on this port number
  -h/--help
    Print this message and exit
"""

import BaseHTTPServer

import sys
import os
import logging
import datetime
import getopt

# http://appscript.sourceforge.net/py-appscript/doc/appscript-manual/index.html
# sudo  /usr/bin/easy_install-2.6 appscript
import appscript
import osax

# To find out what commands are available open up AppleScript Editor
# and then select file Open Dictionary and then open iTunes and look
# in the ITunes suite.

itunes = appscript.app('itunes')
sa = osax.OSAX()

content_types = {'.ico': 'image/x-icon',
                 '.gif': 'image/gif',
                 '.jpg': 'image/jpg',
                 '.png': 'image/png',
                 '.css': 'text/css',
                 '.html': 'text/html',
                 '.js': 'text/javascript',
                 }

def usage(code, msg=''):
  if code:
    fd = sys.stderr
  else:
    fd = sys.stdout
  PROGRAM = os.path.basename(sys.argv[0])
  print >> fd, __doc__ % locals()
  if msg:
    print >> fd, msg
  sys.exit(code)


class iTunesControl(BaseHTTPServer.BaseHTTPRequestHandler):

  def do_GET(self):
    try:
      methods = {'do': self.do_do,
                 }

      path = self.path.split('/')
      # logging.info('path: %r', path)

      if len(path) > 1 and path[1] in methods:
        methods[path[1]](path[1:])
        return
      else:
        if len(path) < 2 or not path[1]:
          path = ['', 'control.html']
        self.do_static(path)
      return
    except IOError:
      self.send_error(404, 'File Not Found: %s' % self.path)

  def do_static(self, path):
    file_name = path[1]
    ext = os.path.splitext(file_name)[1]
    self.send_response(200)
    self.send_header('content-type', content_types.get(ext, 'text/html'))
    self.end_headers()

    static_file = os.path.join(os.path.dirname(__file__),
                                'static', file_name)
    # logging.info('loading %r', static_file)
    self.wfile.write(open(static_file).read())



  def do_do(self, path):
    action = path[1]
    # logging.info('doing: %r', action)

    methods = {'play': itunes.play,
               'stop': itunes.stop,
               'pause': itunes.pause,
               'prev': itunes.previous_track,
               'next': itunes.next_track,
               'volup': self.do_volup,
               'voldown': self.do_voldown,
               }


    # itunes.player_position()
    # 6
    # >>> itunes.player_state()
    # k.playing
    # >>> itunes.current_track().time()
    # u'3:04'

    if action in methods:
      methods[action]()

    self.send_response(204)  # TODO(ark) make these all XML HTTP req?
    self.end_headers()


  def do_volup(self):
    itunes.sound_volume.set(min(100, itunes.sound_volume() + 10))


  def do_voldown(self):
    itunes.sound_volume.set(max(0, itunes.sound_volume() - 10))


def run(server_class=BaseHTTPServer.HTTPServer,
        handler_class=iTunesControl,
        port=8000):
  server_address = ('', port)
  httpd = server_class(server_address, handler_class)
  display_server_address(server_address)
  httpd.serve_forever()


def display_server_address(server_address):
  server_address = list(server_address)
  if not server_address[0]:
    server_address[0] = 'localhost'
  if server_address[1] == 80:
    server_address[1] = ''
  else:
    server_address[1] = ':%d' % server_address[1]
  logging.info('Starting to listen on http://%s/', ''.join(server_address))


if __name__ == '__main__':
  began = str(datetime.datetime.today())
  logging.basicConfig()
  logging.getLogger().setLevel(logging.DEBUG)
  try:
    opts, args = getopt.getopt(sys.argv[1:], 'hp:',
                               ['help', 'port='])
  except getopt.error, msg:
    usage(1, msg)

  if args:
    usage(1)
  port = 8000
  for opt, arg in opts:
    if opt in ('-h', '--help'):
      usage(0)
    if opt in ('-p', '--port'):
      port = int(arg)

  logging.debug("Starting %s @ %s", " ".join(sys.argv), began)

  run(port=port)
